#
# \file
# \brief
# \author Marco Antonio Pinto Orellana
#
# -------------------------------------------------------------------------
#
# Copyright (C) 2012  (see AUTHORS file for a list of contributors)
# http://opentonitruum.sourceforge.net
#
# This file is part of OpenTonitruum - a simulator/library of signal trans-
# mission, modulation and processing in a wireless environment.
#
# OpenTonitruum is free software: you can redistribute it and/or modify it 
# under the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at 
# your option) any later version.
#
# OpenTonitruum is distributed in the hope that it will be useful, but WITH-
# OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with OpenTonitruum.  If not, see <http://www.gnu.org/licenses/>.
#
# -------------------------------------------------------------------------
#
from SimPy.Simulation import *
from DataStructure import *


class CircuitReceiver(Process):
	def __init__(self, medium):
		Process.__init__(self)
		self.medium = medium
		self.on = False
		self.buffer = Buffer(1024*8)
		self.notify = Event()
		
	def run(self):
		while True:
			yield waituntil, self, lambda: self.on
			yield waitevent, self, self.medium.transmitionEnd
			self.buffer.push(self.medium.listen())
			bits = self.medium.listen()
			if hasattr(bits, "__iter__"):
				for bit in bits: self.notify(self, bit)
			else:
				self.notify(self, bits)

				
class CircuitTransmissor(Process):
	def __init__(self, medium):
		Process.__init__(self)
		self.medium = medium
		self.on = False
		self.parallelBitNumber = medium.parallelBitNumber
		self.buffer = Buffer(1024*8)
		self.notify = Event()
	
	def run(self):
		while True:
			yield waituntil, self, lambda: self.on
			while not self.buffer.empty():
				yield waituntil, self, lambda: not self.medium._transmitting
				bits = self.buffer.pop()
				for bit in bits: self.medium.transmit(self, bit)
				yield waituntil, self, lambda: not self.medium._transmitting
			if hasattr(bits, "__iter__"):
				for bit in bits: self.notify(self, bit)
			else:
				self.notify(self, bits)
			self.on = False


class Transreceiver(object):
	def __init__(self, id, medium, flag = [0]):
		self.id = id
		self.tx = CircuitTransmissor(medium)
		self.rx = CircuitReceiver(medium)
		self.rx.notify.add(self.receive)
		self.tx.notify.add(self.transmitEnd)
		self.rx.on = True
		self.flag = flag
		activate(self.tx, self.tx.run())
		activate(self.rx, self.rx.run())
	
	def send(self, bits):
		if len(bits) > self.tx.buffer.maximum:
			raise Exception("Transmission buffer exceeded.")
		
		self.tx.buffer.push(self.insertZeroBits(bits))
		self.tx.on = True
	
	def receive(self, target, bit):
		pass
	
	def transmitEnd(self, target, bit):
		pass
	
	def insertZeroBits(self, bits):
		nbits = self.flag[:]
		haveOne = 0
		for bit in bits[len(self.flag):][:-len(self.flag)]:
			if haveOne == 5:
				nbits.append(0)
				nbits.append(bit)
				haveOne = 0
			else:
				nbits.append(bit)
				haveOne = (haveOne + 1 if bit == 1 else 0)
		return nbits + [0] * ( len(nbits) % self.tx.parallelBitNumber ) + self.flag[:]
	
	def removeZeroBits(self, bits):
		nbits = self.flag[:]
		haveOne = 0
		for bit in bits[len(self.flag):][:-len(self.flag)]:
			if haveOne == 5:
				haveOne = 0
				continue
			else:
				nbits.append(bit)
				haveOne = (haveOne + 1 if bit == 1 else 0)
		return nbits + self.flag[:]# + [0] * ( len(nbits) % self.tx.parallelBitNumber ) + self.flag[:]
